package core;

import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Observable;

import javax.swing.JOptionPane;
import javax.swing.Timer;

import projectiles.Bullet;
import projectiles.Cannonball;
import projectiles.Missile;
import projectiles.Nuke;
import projectiles.Plasmaball;
import projectiles.Projectile;
import superweapons.Blizzard;
import superweapons.Firestorm;
import superweapons.NukePlane;
import superweapons.SuperWeapon;
import towers.Tower;
import DB.Database;
import enemies.Enemy;
import enemies.Infantry;
import enemies.Jeep;
import enemies.Tank;

public class Model extends Observable {
	
	private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
	private ArrayList<Enemy> enemies = new ArrayList<Enemy>();
	private ArrayList<Tower> towers = new ArrayList<Tower>();
	private ArrayList<Explosion> explosions = new ArrayList<Explosion>();
	private ArrayList<SuperWeapon> superWeapons = new ArrayList<SuperWeapon>();
	
	private Map map;
	private Statistics stats;
	private Timer timer;
	private Launcher launcher;
	
	private boolean blizzard = false;
	
	private boolean hasEnded = false;
	
	private boolean isMapEditor;
	private String userName;
	private String userEmail;
	
	private String firstWave = "Infantry";
	private String secondWave = "Jeep";
	
	// Nodig om te kijken of er projectielen etc buiten het scherm vallen
	public static final int battlefieldWidth = 780;
	public static final int battlefieldHeight = 425;

	public final static double timerInterval = 0.04; // 25x per sec
	
	private int difficulty;
	private int highestScore = -1;
	
	// Deze worden gebruikt voor mapeditor
	private int huidigeRoute = 0;

	public Model( Launcher launcher, Map map, int difficulty, boolean isMapEditor ) {
		timer = new Timer( (int)(1000 * timerInterval), new TimerHandler() );
		timer.start();
		
		this.stats = new Statistics( this );
		this.map = map;
		this.launcher = launcher;
		this.difficulty = difficulty;
		this.isMapEditor = isMapEditor;
	}
	
	public boolean hasEnded()
	{
		return hasEnded;
	}
	
	public boolean isMapEditor()
	{
		return isMapEditor;
	}
	
	public int getHuidigeRoute()
	{
		return huidigeRoute;
	}
	
	public void startGame()
	{
		if( map.getBase() == null )
		{
			setChanged();
			notifyObservers("status geen basis");
		}
		else
		{
			// Verwijder alle lege routes
			int i = 0;
			while ( i < map.getRoutes().size())
			{
				if( map.getRoutes().get(i).size() == 0 )
					map.getRoutes().remove(i);
				else
					i++;
			}
			
			// Checken of alle routes eindigen in de basis
			for( ArrayList<Point2D.Double> route : map.getRoutes() )
			{
				Point2D.Double p = route.get(route.size() - 1);
				if ( !map.getBase().getBounds().intersects((p.x - Map.wayWidth / 2), (p.y - Map.wayWidth / 2), Map.wayWidth * 0.75, Map.wayWidth * 0.75))
				{
					setChanged();
					notifyObservers("status route eindigt niet in basis");
					return;
				}
			}
			
			isMapEditor = false;
			
			setChanged();
			notifyObservers("reset");
		}
	}
	
	/**
	 * @param p
	 * @return boolean Geeft true terug als punt op de basis is 
	 */
	public boolean addPointToRoute( Point p )
	{
		if ( this.map.getRoutes().size() == huidigeRoute )
		{
			// Dit zal het eerste punt van de route worden, eerst checken of dit punt NIET op de basis gestart word
			if ( map.getBase() != null && map.getBase().getBounds().intersects((p.x - Map.wayWidth / 2), (p.y - Map.wayWidth / 2), Map.wayWidth * 0.75, Map.wayWidth * 0.75) )
			{
				// Eerste punt mag niet op de basis zijn, doe niets
				return true;
			}
			
			this.map.getRoutes().add( new ArrayList<Point2D.Double>() );
		}
		
		setChanged();
		notifyObservers("status klaar");
		
		this.map.getRoutes().get(huidigeRoute).add( new Point2D.Double(p.x, p.y) );
		
		if ( map.getBase() != null && map.getBase().getBounds().intersects((p.x - Map.wayWidth / 2), (p.y - Map.wayWidth / 2), Map.wayWidth * 0.75, Map.wayWidth * 0.75) )
		{
			huidigeRoute++;
			
			setChanged();
			notifyObservers("status nieuwe route");
			
			return true;
		}
		
		return false;
	}
	
	public void verwijderLaatstePointOfRoute()
	{
		// Voor het geval dat je net een nieuwe lege route hebt
		if( huidigeRoute >= map.getRoutes().size() )
			huidigeRoute = map.getRoutes().size() - 1;
		
		ArrayList<Point2D.Double> route = map.getRoutes().get(huidigeRoute);
		if ( route.size() == 0 )
		{
			map.getRoutes().remove(huidigeRoute);
			
			if ( huidigeRoute > 0 )
			{
				huidigeRoute--;
				verwijderLaatstePointOfRoute();
			}
		}
		else
			route.remove(route.size()-1);
	}
	
	public void placeBase( Point p )
	{
		this.map.setBase( new Base(new Point2D.Double(p.x, p.y)) );
		
		setChanged();
		notifyObservers("status basis geplaatst");
	}
	
	/**
	 * @param wave
	 * @return aantal enemies dat er komen voor dat level
	 */
	public int getCountEnemies( int wave ) {
		return (int)(wave / 3.0 + 1);
	}
	
	/**
	 * Volgende wave van enemies
	 */
	public void nextWave(){
		if ( stats.getWave() < 100 && map.getBase().getHealth() > 0 && !hasEnded() && !isPaused() )
		{
			stats.updateNextWave();
			
			// Level verhogen
			this.stats.setWave( this.stats.getWave() + 1 );
			
			new Thread( new WaveThread( this, getCountEnemies( stats.getWave() ) ) ).start();
			
			//first en second bepalen
			int rand1 = (int) (Math.random() * 3);
			firstWave = secondWave;
			if(rand1 == 0){
				secondWave = "Tank";
			}if(rand1 == 1){
				secondWave = "Jeep";
			}if(rand1 == 2){
				secondWave = "Infantry";
			}
			
			setChanged();
			notifyObservers( "nextwave" );
			
			setChanged();
			notifyObservers( "update" );
		}
	}
	
	public boolean buyTower( Tower tower, Point2D.Double p ){
		if( map.getBase().getHealth() > 0 && stats.getMoney() >= tower.getCost()  ){

			stats.setMoney( stats.getMoney() - tower.getCost() );
			tower.setPosition( p );
			tower.calcBounds();
			towers.add( tower );
			
			// Laat View weten dat we moeten repainten
			setChanged();
			notifyObservers( "repaint" );
			
			return true;		
		}
		return false;
	}

	/**
	 * @return the map
	 */
	public Map getMap() {
		return map;
	}

	/**
	 * @return the enemies
	 */
	public ArrayList<Enemy> getEnemies() {
		return enemies;
	}

	/**
	 * @param enemies
	 *            the enemies to set
	 */
	public void setEnemies(ArrayList<Enemy> enemies) {
		this.enemies = enemies;
	}

	/**
	 * @return the projectiles
	 */
	public ArrayList<Projectile> getProjectiles() {
		return projectiles;
	}

	/**
	 * @param projectiles
	 *            the projectiles to set
	 */
	public void setProjectiles(ArrayList<Projectile> projectiles) {
		this.projectiles = projectiles;
	}

	/**
	 * @return the towers
	 */
	public ArrayList<Tower> getTowers() {
		return towers;
	}

	/**
	 * @return the explosions
	 */
	public ArrayList<Explosion> getExplosions() {
		return explosions;
	}

	/**
	 * @param towers
	 *            the towers to set
	 */
	public void setTowers(ArrayList<Tower> towers) {
		this.towers = towers;
	}
	
	public Statistics getStats() {
		return stats;
	}
	
	public void togglePause()
	{
		if ( timer.isRunning() )
		{
			timer.stop();
			
			stats.paused();
		}
		else
		{
			timer.start();
			
			stats.unpaused();
		}
		
		setChanged();
		notifyObservers( "repaint" );
		notifyObservers("Pauze");
	}
	
	public boolean isPaused()
	{
		return !timer.isRunning();
	}
	
	public boolean repair(Tower t) {	
		if ( t != null
		&& t.getHealth() > 0
		&& t.getHealth() < t.getMaxHealth()
		&& t.getPosition() != null
		&& stats.getMoney() >= t.getMoneyRequiredForRepair()
		) {
			stats.reduceMoney(t.getMoneyRequiredForRepair());
			t.setHealth( t.getMaxHealth() );
			
			// Repaint de health die erbij staat
			setChanged();
			notifyObservers( "repaint" );
			return true;
		}
		return false;
	}
	
	public boolean upgrade(Tower t) {	
		if ( t != null
		&& t.getHealth() > 0
		&& t.getLevel() < t.getMaxLevel()
		&& t.getPosition() != null
		&& (
				this.repair(t) || t.getHealth() == t.getMaxHealth()
			)
		&& stats.getMoney() >= t.getMoneyRequiredForUpgrade()
		) {
			stats.reduceMoney(t.getMoneyRequiredForUpgrade());
			t.updateLevel();
			
			// Repaint de health/level die erbij staat
			setChanged();
			notifyObservers( "repaint" );
			return true;
		}
		return false;
	}
	
	public boolean sell(Tower t) {
		if ( t != null && t.getHealth() > 0 && t.getPosition() != null )
		{
			towers.remove(t);
			
			stats.increaseMoney(t.getSellProfit());
			
			t.setHealth(0);
			
			//Tower doet boom!
			explosions.add( new Explosion( t.getMiddle(), 50) );
			
			setChanged();
			notifyObservers( "repaint" );
			
			return true;
		}
		return false;
	}
	
	/**
	 * repainten van scherm
	 */
	public void repaint(){
		setChanged();
		notifyObservers( "repaint" );
	}
	

	/**
	 * @return the firstWave
	 */
	public String getFirstWave() {
		return firstWave;
	}

	/**
	 * @return the secondWave
	 */
	public String getSecondWave() {
		return secondWave;
	}
	
	/**
	 * @return the firstWave
	 */
	public void showInputName(){
		if( userName == null && userEmail == null) {
			userName = JOptionPane.showInputDialog("What is your name?");
			if( userName != null ) {
				userEmail = JOptionPane.showInputDialog("What is your email?");
			}
		}
		
		getStats().setName(userName);
		getStats().setEmail(userEmail);
	}
	
	public void showHighScore(){
		setChanged();
		notifyObservers( "highscore" );
	
	}
	
	/**
	 * @param punt p van locatie muis, en towerobject van geselecteerde object
	 * @return true of false
	 * controleerd of een punt bezet is.
	 */
	public boolean placeOccupied( Point p, Tower selectedItem ){
		for( Tower t : towers ){
			//omdat de toren wordt gebouw waar je klikt (midden) moet er links en rechts
			//de helft van de toren beschikbaar zijn
			if( t.bounds.intersects( p.x-(selectedItem.getSize().getWidth()/2), p.y-(selectedItem.getSize().getHeight()/2), selectedItem.getSize().getWidth(), selectedItem.getSize().getHeight())){
				return true;
			}
		}
		if( isOnRoad(p, selectedItem) || isOnBase(p, selectedItem) || !isInField(p, selectedItem) ){
			return true;
		}
		return false;
	}
	
	/**
	 * @param punt p van locatie muis, en towerobject van geselecteerde object
	 * @return true of false
	 * controleerd of een punt bezet is op de weg
	 */
	private boolean isOnRoad( Point p, Tower selectedItem){
		for(Polygon y : map.getPolygonArray()){
			if(y.intersects((p.x-selectedItem.image.getIconWidth()/2), (p.y - selectedItem.image.getIconHeight()/2), selectedItem.image.getIconWidth(), selectedItem.image.getIconHeight() )){
				return true;
			}
		}
		return false;
		//return model.getMap().getPolygon().intersects(p.x, p.y, selectedItem.image.getIconWidth(), selectedItem.image.getIconHeight() );
	}
	
	/**
	 * @param punt p van locatie muis, en towerobject van geselecteerde object
	 * @return true of false
	 * controleerd of een punt bezet is op de basis
	 */
	private boolean isOnBase(Point p, Tower selectedItem){
		return map.getBase().getBounds().intersects((p.x-selectedItem.image.getIconWidth()/2), (p.y - selectedItem.image.getIconHeight()/2), selectedItem.image.getIconWidth(), selectedItem.image.getIconHeight());
	}
	
	/**
	 * @param punt p van locatie muis, en towerobject van geselecteerde object
	 * @return true of false
	 * controleerd of er wel in het veld geklikt wordt.
	 */
	private boolean isInField( Point p, Tower selectedItem ){
		if( p.x >= (selectedItem.getSize().getWidth() / 2) && p.y >= (selectedItem.getSize().getHeight() / 2) && p.x < (battlefieldWidth - selectedItem.getSize().getWidth() / 2) && p.y < (battlefieldHeight - selectedItem.getSize().getHeight() / 2) )
			return true;
		
		return false;
	
	}
	
	/**
	 * @param punt p van locatie muis
	 * @return gevonden tower object
	 * kijkt of een punt een locatie van tower is
	 */
	public Tower getTowerByPoint( Point p ){
		for( Tower t : towers ){
			if( t.bounds.intersects( p.x, p.y, 5, 5 ) ){
				return t;
			}
		}
		
		return null;
	}
	
	public void abandon() {
		map.getBase().setHealth(0);
		
		repaint();
	}
	
	class TimerHandler implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			
			if ( isMapEditor() )
			{
				setChanged();
				notifyObservers( "repaint" );
				return;
			}
			
			// Moeten we repainten?
			boolean repaint = false;
			
			if ( stats.getWave() >= 100 && enemies.size() == 0 )
			{
				timer.stop();
				hasEnded = true;
				
				setChanged();
				notifyObservers( "repaint" );
				
				showInputName();
				stats.insertStats();
				showHighScore();
			}
			
			// Spel is afgelopen als basis kapot is
			// We hoeven niets meer up te daten of te redrawen, alles behalve de explosies
			// Als health van basis 0 is, dan doe explosie
			else if( map.getBase().getHealth() <=  0 ) {
				
				timer.stop();
				hasEnded = true;
				
				setChanged();
				notifyObservers( "repaint" );
			}
			else
			{
				if ( !isPaused() )
				{
					// Stats updaten als spel niet gepauzeerd is
					stats.update();
				
					setChanged();
					notifyObservers( "stats" );
					
					// next wave
					if ( stats.getWave() < 100 && stats.getNextWave() <= 0 )
						nextWave();
				}
			
				// Bijhouden welke units weg mogen
				ArrayList<Enemy> deadEnemies = new ArrayList<Enemy>();
				ArrayList<Projectile> deadProjectiles = new ArrayList<Projectile>();
				ArrayList<Tower> deadTowers = new ArrayList<Tower>();
				ArrayList<SuperWeapon> deadSuperWeapons = new ArrayList<SuperWeapon>();
				
				// Torens loop
				for( Tower t : towers )
				{
					if ( t.update() )
						repaint = true;
					
					if(t.getNukedCount() > 500)
						deadTowers.add(t);
					
					// Torens laten schieten
					Collections.shuffle( enemies );
					for( Enemy en : enemies )
					{
						if ( en.isOnRoad() && !en.isOutsideView() && t.getAimAtEnemy() == null &&!en.isOutsideView() && en.getHealth() > 0 && en.position.distance( t.position ) <= t.range )
						{
							t.setAimAtEnemy( en );
						}
						
						if( en.isOnRoad() && !en.isOutsideView() && t.getAimAtEnemy() != null && en.position.distance( t.position ) <= t.range ){
							if ( t.canShoot( ) )
							{
								projectiles.add( t.shoot() );
								repaint = true;
							}
						}
					}
				}
			
				// Superweapons loop
				for(SuperWeapon sw : superWeapons)
				{
					if(sw.update())
						repaint = true;
				}
				
				// Enemies loop
				for( Enemy en : enemies )
				{
					if ( en.update() )
						repaint = true;
					
					if(en.getNukedCount() > 500)
						deadEnemies.add(en);
					
					if(en.fireStorm)
						en.setSpeed((int)Math.pow(en.getSpeed(), 0.5));
					
					if(en.fireStorm && en.fireStormTime2 > en.fireStormTime){
						deadEnemies.add(en);
						explosions.add( new Explosion( en.getMiddle(), 30) );
					}
	
					// Enemies in de basis verwijderen
					if(en.getHealth() > 0 && en.bounds.intersects(map.getBase().position.x, map.getBase().position.y, map.getBase().getSize().getWidth(), map.getBase().getSize().getHeight())) {
						
						// De enemy kan niets meer doen
						en.setHealth(0);
						
						//Enemy verwijderen
						deadEnemies.add(en);
						
						//Base health verminderen
						map.getBase().setHealth( Math.max( map.getBase().getHealth() - 1, 0 ) );
					}
					
					// Enemies laten schieten
					Collections.shuffle( towers );
					for( Tower t : towers )
					{
						if (en.isOnRoad() && !en.isOutsideView() && en.getAimAtTower() == null && en.position.distance( t.position ) <= en.range )
						{
							en.setTower( t );
						}
						
						if(en.isOnRoad() &&!en.isOutsideView() && en.getAimAtTower() != null && en.position.distance( t.position ) <= en.range){
							if ( en.canShoot( ) )
							{
								projectiles.add( en.shoot() );
								repaint = true;
							}
						}
					}
				}
				
				// Projectile kan wat raken
				ArrayList<ShootingUnit> shootingUnits = new ArrayList<ShootingUnit>();
				shootingUnits.addAll( towers );
				shootingUnits.addAll( enemies );
				
				// Projectiles loop
				for( Projectile t : projectiles )
				{
					if ( t.update() )
						repaint = true;
						
					if ( t.isOutsideView() )
					{
						deadProjectiles.add( t );
						continue;
					}
					
					// Nuke controleren
					if ( t instanceof Nuke ){
						Nuke n = (Nuke) t;
						
						// Nen nieuwe enemy toewijzen als nuke geen (levende) vijand heeft
						if( n.getEnemy() == null || n.getEnemy().getHealth() <= 0){
							n.calcEnemyForNuke( enemies );
						}
						
					}
					
					for( ShootingUnit en : shootingUnits ){
						if ( t.bounds.intersects( en.getPosition().x, en.getPosition().y, en.getSize().getWidth(), en.getSize().getHeight()))
						{
							// Ze mogen niet op hetzelfde type schieten
							if ( (t.getOrigin() instanceof Tower && en instanceof Enemy) || (t.getOrigin() instanceof Enemy && en instanceof Tower) )
							{
								int damage = (int)(t.getDamage() * t.getOrigin().getDamageMultiplier());
								int health = Math.max( 0, en.getHealth() - damage );
								if ( health == 0 )
								{
									if ( en instanceof Enemy )
									{
										stats.incrementKills();
										// Je krijgt geld erbij als je een enemy afmaakt
										// de wortel van level zodat als level hoger word, je niet teveel krijgt
										// en + 10 zodat je niet te weinig krijgt in de eerste levels
										//stats.setMoney( (int) (stats.getMoney() + (Math.sqrt( stats.getWave() ) + 10) ) );
										stats.setMoney(myCash(en,t,null));
										deadEnemies.add( (Enemy)en );
										
										// Nuke explodeert
										if ( t instanceof Nuke ){
											explosions.add( new Explosion( t.getMiddle(), 40) );
										}
									}
									else if ( en instanceof Tower)
									{
										deadTowers.add( (Tower)en );
										
										// Tower doet boom!
										explosions.add( new Explosion( en.getMiddle(), 50) );
									}
								}
								
								en.setHealth( health );
								
								// Projectile ook verwijderen
								deadProjectiles.add( t );
							}
						}
					}
				}
				
				//superwapens kunnen wat raken
				for(SuperWeapon s : superWeapons)
				{
															
					if(s instanceof NukePlane){
						NukePlane p = (NukePlane) s;
						if(p.getPosition().x > battlefieldWidth + p.getSize().width || p.getPosition().y > battlefieldHeight + p.getSize().getHeight()){
							deadSuperWeapons.add(s);
						}
						if(!p.getBombsAway() && p.getNuke() != null){
							explosions.add(new Explosion(new Point2D.Double(p.getNuke().getPosition().x+p.getNuke().getSize().height/2, p.getNuke().getPosition().y+p.getNuke().getSize().height/2), 100));
							p.setBombsAway(true);
						}
						if(p.getNuke() != null && p.getNuke().isActive()){
							for(Tower to : towers){
								if(p.getNuke().getBounds().intersects(to.getPosition().x, to.getPosition().y, to.getSize().getWidth(), to.getSize().getHeight()) && to.getHealth() > 0){
									to.SetNuked();
									explosions.add( new Explosion( to.getMiddle(), 50) );
								}
							}
							
							for(Enemy en : enemies){
								if(p.getNuke().getBounds().intersects(en.getPosition().x, en.getPosition().y, en.getSize().getWidth(), en.getSize().getHeight()) && en.getHealth() > 0){
									en.SetNuked();
									en.setSpeed(0);
									explosions.add( new Explosion( en.getMiddle(), 50) );
									stats.incrementKills();
									stats.setMoney(myCash(null,null,s));
									//stats.setMoney( (int) (stats.getMoney() + (Math.sqrt( stats.getLevel() ) + 10) ) );
								}
							}
						}
					}else{
						for(Enemy en : enemies){
							if(s.getBounds().intersects(en.getPosition().x, en.getPosition().y, en.getSize().getWidth(), en.getSize().getHeight()) && en.health > 0){
								//en.setHealth(0);
								//deadEnemies.add(en);
								//explosions.add( new Explosion( en.getMiddle(), 50) );
								en.moveObjectFireStorm();
								stats.incrementKills();
								stats.setMoney(myCash(null,null,s));
								//stats.setMoney( (int) (stats.getMoney() + (Math.sqrt( stats.getLevel() ) + 10) ) );
							}
						}
					}
				}
				
				// Verwijder dead units
				for( Enemy en : deadEnemies ){
					repaint = true;
					enemies.remove( en );
				}
				deadEnemies.clear();

				for( Projectile p : deadProjectiles ){
					repaint = true;
					projectiles.remove( p );
				}
				deadProjectiles.clear();
				
				for( Tower t : deadTowers ){
					repaint = true;
					towers.remove( t );
				}
				deadTowers.clear();
				
				for( SuperWeapon sw : deadSuperWeapons ){
					repaint = true;
					superWeapons.remove( sw );
				}
				deadSuperWeapons.clear();
				
				// Update stats
				setChanged();
				notifyObservers( "updateStats" );
			}
			
			// Update explosions en verwijder explosions die klaar zijn
			int k = 0;
			while( k < explosions.size())
			{	
				repaint = true;
				
				if ( explosions.get(k).isDone() )
					explosions.remove(k);
				else
					k++;
			}
			
			// Laat view weten dat we graag willen repainten
			if ( repaint ) {
				setChanged();
				notifyObservers( "repaint" );
			}
			
			// Elke timer tik de stats laten updaten
			stats.update();
		}

	}
	
	private int myCash(ShootingUnit en, Projectile t,SuperWeapon s)
	{
		int my_cash = stats.getMoney();
		int cash_bonus = 0;
		/**
		 * bonus punten
		 * hoe kleiner de waarde des te meer bonus punten
		 * wordne toegekend
		 */
		int bullet_bonus = 1;
		int cannonball_bonus = 2;
		int nuke_bonus = 3;
		int plasmaball_bonus = 4;
		int missile_bonus = 5;
		// cash super weapons
		int plane_bonus = 1;
		int firestorm_bonus = 1;
		int blizzard_bonus = 2;
		
		if(en != null && s == null)
		{
			if(en instanceof Enemy )
			{
				if(en instanceof Tank)
					cash_bonus = 5;
				else if(en instanceof Jeep)
					cash_bonus = 4;
				else if(en instanceof Infantry)
					cash_bonus = 3;
			}
			if(t instanceof Nuke)
				my_cash += cash_bonus - nuke_bonus;
			else if(t instanceof Bullet)
				my_cash += cash_bonus - bullet_bonus;
			else if(t instanceof Missile)
				my_cash += cash_bonus - missile_bonus;
			else if(t instanceof Cannonball)
				my_cash += cash_bonus - cannonball_bonus;
			else if(t instanceof Plasmaball)
				my_cash += cash_bonus - plasmaball_bonus;
		}
		else if (en == null && s != null)
		{
			if(s instanceof Blizzard)
				my_cash += blizzard_bonus;
			else if(s instanceof Firestorm)
				my_cash += firestorm_bonus;
			else if(s instanceof NukePlane)
			{
				my_cash += plane_bonus;
			}
		}
		return( my_cash + cash_bonus ) ;
	}
	
	public Launcher getLauncher() 
	{
		return launcher;
	}
	
	public boolean buySuperWeapon( SuperWeapon w, Point2D.Double p ){
		if( map.getBase().getHealth() > 0 ){
			String weapon = w.getClass().getName();
			String[] stuff = weapon.split("\\.");
			SuperweaponController c = Controller.main.getSuperweapon(stuff[stuff.length-1]);
			c.resetTimer();
			
			if(w instanceof Blizzard){
				blizzardOn();
				
			}else if(w instanceof NukePlane){
				NukePlane plane = (NukePlane) w;
				plane.setPosition(new Point2D.Double((double) 0-plane.getSize().width, p.y-plane.size.height/2));
				plane.setPoint((int)p.x-plane.size.width/2, (int)p.y-plane.size.height/2);
				plane.setViewAngle(270);
				superWeapons.add(plane);
			}else if(w instanceof Firestorm){
				Firestorm storm = (Firestorm) w;
				storm.setPosition(new Point2D.Double(p.x-storm.size.width/2, p.y-storm.size.height/2));
				superWeapons.add(storm);
				Timer t = new Timer( 10000, new FireStormTimerListener( storm ) );
				t.start();
			}
			
			// Laat View weten dat we moeten repainten
			setChanged();
			notifyObservers( "repaint" );
			
			return true;		
		}
		return false;
	}
	
	public void blizzardOn(){
		if(!blizzard){
			Timer t = new Timer( 60000, new BlizzardTimerListener() );
			
			t.start();
			map.toggleSnow(true);
			//speed huidige items verlagen
			for(Enemy e : enemies){
				e.setSpeed(e.getSpeed()/2);
			}
			//speed nieuwe items verlagen
			blizzard = true;
		}
	}
	
	public void blizzardOff(){
		map.toggleSnow(false);
		//speed huidige items verlagen
		for(Enemy e : enemies){
			e.setSpeed(e.getSpeed()*2);
		}
		//speed nieuwe items verlagen
		blizzard = false;
	}
	
	class BlizzardTimerListener implements ActionListener {

		public void actionPerformed(ActionEvent arg0) {
			blizzardOff();			
		}
		
	}
	
	class FireStormTimerListener implements ActionListener {

		private Firestorm firestorm;
		
		public FireStormTimerListener( Firestorm firestorm ){
			this.firestorm = firestorm;
		}
		
		public void actionPerformed(ActionEvent arg0) {
			superWeapons.remove( firestorm );
			repaint();
		}
		
	}
	
	public ArrayList<SuperWeapon> getSuperWeapons(){
		return superWeapons;
	}
	
	public boolean getBlizzard(){
		return blizzard;
	}
	
	public void setUser(String userName, String userEmail) {
		this.userName = userName;
		this.userEmail = userEmail;
	}
	
	public String getUserName() {
		return userName;
	}


	public String getUserEmail() {
		return userEmail;
	}
	
	public int getDifficulty(){
		return this.difficulty;
	}
	
	public int getHighScore(){
		//Kijken of hij nog niet is opgehaald
		if(this.highestScore == -1){
			highestScore = 0;
			if(this.userEmail != null && this.userName != null && this.userEmail != "" && this.userName != ""){
				Database db = new Database();
				this.highestScore = db.getUserHighScore(this.getUserName(),this.getUserEmail(), this.map.getID(), this.getDifficulty());
			}
		}
		return this.highestScore;
	}
}
